// #include "util.hpp"
// #include "level.hpp"
// #include "message.hpp"
// #include "format.hpp"
// #include "sink.hpp"
#include <unistd.h>
#include "clog.hpp"
// #include "logger.hpp"
// #include "buffer.hpp"

/*
日志落地模块扩展：以时间为间隔进行文件的滚动的日志落地模块
实际上以时间为间隔进行文件滚动，就是以时间段进行滚动
实现思想：
1.用当前系统时间取模规定好的时间段大小，判断当前系统时间处于哪个时间段
2.判断与当前文件所在的时间段是否一致，不一致进行文件切换
*/

enum timeGap
{
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY
};

class RollByTimeSink : public clog::LogSink
{
public:
    using ptr = std::shared_ptr<RollByTimeSink>;
    // 传入文件名，打开文件，将操作句柄管理起来
    RollByTimeSink(const std::string &basename, timeGap gaptype)
        : _basename(basename)
    {
        switch (gaptype)
        {
        case GAP_SECOND:
            _gap_size = 1;
        case GAP_MINUTE:
            _gap_size = 60;
        case GAP_HOUR:
            _gap_size = 3600;
        case GAP_DAY:
            _gap_size = 3600 * 24;
        }
        std::string filename = creatNewFile();
        // 当时间段大小为1时要注意取模的结果
        _cur_gap = _gap_size == 1 ? clog::util::Date::now() : (clog::util::Date::now() % _gap_size); // 获得当前系统所在的时间段
        // 创建目录
        clog::util::File::creatDirectory(clog::util::File::path(filename));
        // 创建文件
        _ofs.open(filename, std::ios::binary | std::ios::app);
        assert(_ofs.is_open());
    }

    void log(const char *data, size_t len) override
    {
        time_t cur_time = clog::util::Date::now();
        if ((cur_time % _gap_size) != _cur_gap)
        {
            _ofs.close();
            // 创建新文件
            _ofs.open(creatNewFile(), std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
        _ofs.write(data, len);
        if (_ofs.good() == false)
        {
            std::cout << "日志文件输出失败！\n";
        }
    }

private:
    std::string creatNewFile()
    {
        // 获取系统时间
        time_t t = clog::util::Date::now();
        struct tm tl;
        localtime_r(&t, &tl);
        std::stringstream ss;
        ss << _basename;
        ss << tl.tm_year + 1900;
        ss << tl.tm_mon + 1;
        ss << tl.tm_mday;
        ss << tl.tm_hour;
        ss << tl.tm_min;
        ss << tl.tm_sec;
        ss << ".log";
        return ss.str();
    }
    std::string _basename;
    std::ofstream _ofs; // 为了避免每次对文件写入都要打开文件，对操作句柄进行管理
    size_t _cur_gap;    // 当前系统所在的时间段
    size_t _gap_size;   // 时间段大小
};

void test_log()
{
    //std::cout<<"///"<<std::endl;
    //clog::Logger::ptr logger = clog::LoggerManager::GetInstance().getRootLogger();
    // clog::Logger::ptr logger = clog::LoggerManager::GetInstance().getLogger("async_logger");
    // std::cout<<clog::LoggerManager::GetInstance().hashLogger("async_logger")<<std::endl;

    clog::Logger::ptr logger=clog::GetLogger("async_logger");
    logger->debug( "%s", "测试日志");
    logger->info("%s", "测试日志");
    logger->warn( "%s", "测试日志");
    logger->error( "%s", "测试日志");
    logger->fatal( "%s", "测试日志");
    int count = 0;
    while (count < 400000)
    {
        logger->fatal("测试日志-%d", count++);
        //std::cout<<"..."<<std::endl;
    }

    // DEBUG( "%s", "测试日志");
    // INFO("%s", "测试日志");
    // WARN( "%s", "测试日志");
    // ERROR( "%s", "测试日志");
    // FATAL( "%s", "测试日志");
    // int count = 0;
    // while (count < 400000)
    // {
    //     FATAL("测试日志-%d", count++);
    //     //std::cout<<"..."<<std::endl;
    // }
}

int main()
{
    // // 测试缓冲区--将一个文件的数据写入缓冲区 再从缓冲区中拿出数据写入另外一个文件 判断两个文件是否相同
    // std::ifstream ifs("./logfile/test.log", std::ios::binary);
    // if (ifs.is_open() == false)
    // {
    //     return -1;
    // }
    // // 读写位置跳到文件末尾
    // ifs.seekg(0, std::ios::end);
    // // 获取此时读写位置距离文件起始位置长度
    // size_t size = ifs.tellg();
    // // 读写位置跳到文件起始位置
    // ifs.seekg(0, std::ios::beg);
    // std::string body;
    // body.resize(size);
    // ifs.read(&body[0], size);
    // if (ifs.good() == false)
    // {
    //     std::cout << "read error!\n";
    //     return -1;
    // }
    // ifs.close();

    // // 写入缓冲区
    // clog::Buffer buffer;
    // for (int i = 0; i < body.size(); i++)
    // {
    //     buffer.push(&body[i], 1);
    // }
    // // 从缓冲区写入另外一个文件
    // std::ofstream ofs("./logfile/temp.log", std::ios::binary);
    // if (ofs.is_open() == false)
    // {
    //     std::cout<<"open file error!/n";
    //     return -1;
    // }
    // size_t rsize = buffer.readAbleSize();
    // for (int i = 0; i < rsize; i++)
    // {
    //     ofs.write(buffer.begin(), 1);
    //     if (ofs.good() == false)
    //     {
    //         std::cout << "write error!\n";
    //         return -1;
    //     }
    //     buffer.movReaderIndx(1);
    // }
    // ofs.close();

    const char *logger_name = "async_logger";
    std::unique_ptr<clog::LoggerBuilder> bd(new clog::GlobalLoggerBuilder());
    bd->buildloggername(logger_name);
    bd->buildformatter("[%c][%p][%f:%l][%m]%n");
    bd->buildEnableUnsaveAsync();
    bd->buildloggerlevel(clog::LogLevel::value::WARM);
    bd->buildloggertype(clog::LoggerType::LOG_ASYNC);
    bd->buildsink<clog::StdoutSink>();
    bd->buildsink<clog::FileSink>("./logfile_test/global_async.log");
    // bd->buildsink<clog::RollBySizeSink>("./logfile/async.log-", 1024 * 1024);
    //clog::Logger::ptr logger = bd->build();
    bd->build();
    test_log();

    // const char *logger_name = "sync";
    // clog::Formatter::ptr fmt(new clog::Formatter("[%d{%H:%M:%S}][%c][%f:%l][%p]%T%m%n"));
    // clog::LogSink::ptr stdout_ptr = clog::SinkFactory::creat<clog::StdoutSink>();
    // clog::LogSink::ptr file_ptr = clog::SinkFactory::creat<clog::FileSink>("./logfile2/test.log");
    // clog::LogSink::ptr roll_ptr = clog::SinkFactory::creat<clog::RollBySizeSink>("./logfile2/file-", 1024 * 1024);
    // std::vector<clog::LogSink::ptr> sinks = {stdout_ptr, file_ptr, roll_ptr};
    // clog::Logger::ptr logger(new clog::SyncLogger(logger_name, clog::LogLevel::value::WARM, fmt,sinks));

    // logger->debug(__FILE__,__LINE__,"%s","测试日志");
    // logger->info(__FILE__,__LINE__,"%s","测试日志");
    // logger->warn(__FILE__,__LINE__,"%s","测试日志");
    // logger->error(__FILE__,__LINE__,"%s","测试日志");
    // logger->fatal(__FILE__,__LINE__,"%s","测试日志");
    // int count=0;
    // int count_size=0;
    // while(count < 500000)
    // {
    //     logger->fatal(__FILE__,__LINE__,"测试日志-%d",count++);
    // }

    // clog::LogMsg msg(clog::LogLevel::value::INFO, 53, "main.c", "root", "日志格式化类测试...");
    // // clog::Formatter fmt("aaaa%%%g%g%g%g%gbbb[%d{%H:%M%S}][%t][%c][%f:%l][%p]%T%m%n");
    // clog::Formatter fmt;
    // std::string str = fmt.format(msg);
    // // std::cout << str << std::endl;

    // clog::LogSink::ptr stdout_ptr = clog::SinkFactory::creat<clog::StdoutSink>();
    // stdout_ptr->log(str.c_str(), str.size());

    // clog::LogSink::ptr file_ptr = clog::SinkFactory::creat<clog::FileSink>("./logfile/test.log");
    // file_ptr->log(str.c_str(), str.size());

    // clog::LogSink::ptr roll_ptr = clog::SinkFactory::creat<clog::RollBySizeSink>("./logfile/file-", 1024 * 1024);
    // int count = 0;
    // int count_num = 0;
    // while (count < 1024 * 1024 * 10)
    // {
    //     std::string temp = str + std::to_string(count_num++);
    //     roll_ptr->log(temp.c_str(), temp.size());
    //     count += temp.size();
    // }

    // clog::LogSink::ptr time_ptr = clog::SinkFactory::creat<RollByTimeSink>("./logfile_time/file-",GAP_SECOND);
    // time_t old = clog::util::Date::now();
    // while (clog::util::Date::now() < old + 5) // 写五秒
    // {
    //     time_ptr->log(str.c_str(), str.size());
    //     usleep(1000); // 控制写入的消息数量
    // }

    // std::cout<<clog::LogLevel::toString(clog::LogLevel::value::DEBUG)<<std::endl;
    // std::cout<<clog::LogLevel::toString(clog::LogLevel::value::INFO)<<std::endl;
    // std::cout<<clog::LogLevel::toString(clog::LogLevel::value::WARM)<<std::endl;
    // std::cout<<clog::LogLevel::toString(clog::LogLevel::value::ERROR)<<std::endl;
    // std::cout<<clog::LogLevel::toString(clog::LogLevel::value::FATAL)<<std::endl;
    // std::cout<<clog::LogLevel::toString(clog::LogLevel::value::OFF)<<std::endl;

    // std::cout<<clog::util::Date::now()<<std::endl;
    // clog::util::File::creatDirectory(clog::util::File::path("./abc/bcd/a.txt"));

    return 0;
}